package com.paradogs.framework.core.annoations.rpc;

import com.paradogs.framework.core.annoations.base.BaseImportSelector;
import com.paradogs.framework.core.annoations.base.BaseScanner;
import com.paradogs.framework.core.msg.PRMsg;
import com.paradogs.framework.core.msg.route.MsgMapping;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Method;

/**
 * @author: yumi
 * @date: 2023/8/13  16:39
 * @Description: TODO
 */
@Slf4j
public class PRRPCProxyBeanImportSelector extends BaseImportSelector {

    @Override
    public BaseScanner getScanner(BeanFactory beanFactory) {
        // 转换为 DefaultListableBeanFactory 便于操作
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        // 自定义扫描器，获取 BeanDefinitionHolder
        PRRPCInterfaceScanner scanner = new PRRPCInterfaceScanner(defaultListableBeanFactory);
        return scanner;
    }

    @Override
    public void handle(BeanDefinition beanDefinition) {

        registerRPCMapping(beanDefinition);

        registerProxyBean(beanDefinition);

    }

    /**
     * 注册 RPC 响应映射
     * @param beanDefinition
     */
    private void registerRPCMapping(BeanDefinition beanDefinition) {

        try {
            Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
            Method[] methods = beanClass.getDeclaredMethods();

            for (Method method : methods) {
                // 计算路由
                PRRPCMapping mapping = AnnotationUtils.findAnnotation(method, PRRPCMapping.class);
                String route = mapping.value() + "|resp";

                if (PRRPCHolder.getMappingMap().containsKey(route)) {
                    throw new RuntimeException("Duplicate route found: [" + route + "]");
                }

                // 保存 Msg 类型和要执行的方法
                try {
                    // 异步 Async
//                    if (pdgRPCMapping.returnType() == BaseMsg.class && !method.getReturnType().isAssignableFrom(CompletableFuture.class)) {
//                        throw new RuntimeException("RPC[" + pdgRPCMapping.value() + "] use async but returnType is null");
//                    }
//                    if (!method.getReturnType().equals(Void.TYPE) && !method.getReturnType().isAssignableFrom(CompletableFuture.class)) {
//                        throw new RuntimeException("RPC[" + PRRPCMapping.value() + "] return must use async.(CompleteFuture)");
//                    }
//                    Class<? extends BaseMsg> genericReturnType = null;
//                    try {
//                        genericReturnType = (Class<? extends BaseMsg>) ReflectUtils.getGenericReturnType(method);
//                    } catch (Exception e) {
//                        throw new RuntimeException("GetGenericReturnType error, ReturnType[" + method.getReturnType() + "] must extends BaseMsg: " + method.getName());
//                    }
//                    // PdgRpcMapping.returnType default == BaseMsg.class
//                    Class<? extends BaseMsg> targetMsgClass = PRRPCMapping.returnType() == BaseMsg.class ? genericReturnType : PRRPCMapping.returnType();


                    if (PRRPCHolder.getMappingMap().containsKey(route)) {
                        throw new RuntimeException("Route already exist: " + route);
                    }
                    Class<? extends PRMsg> targetMsgClass = (Class<? extends PRMsg>) method.getReturnType();
                    PRRPCHolder.getMappingMap().put(route, new MsgMapping(targetMsgClass, method, false));
                    log.debug("Register RPC callback mapping: [{}]", route);

                } catch (Exception e) {
                    throw new RuntimeException("RPC[" + mapping.value() + "] return must extends BaseMsg(?GCMsg)");
                }
            }


        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 注册代理
     * @param beanDefinition
     */
    private void registerProxyBean(BeanDefinition beanDefinition) {
        try {

            try {
                // 获取当前被扫描到到接口的具体 class name
                String beanClassName = beanDefinition.getBeanClassName();
                // 装载 class
                Class<?> targetInterface = Class.forName(beanClassName);

                // 为该自定义的代理实现类，提供构造方法所需要的原始接口类型参数
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(targetInterface);

                // 修改被扫描接口到具体实现类型，替换为自定义到代理实现类
                String originBeanName = beanDefinition.getBeanClassName();
                beanDefinition.setBeanClassName(PRRPCProxyBean.class.getName());

                log.debug("Proxy RPC interface: [{}]", originBeanName);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}
